/* main.c */
#include "app_inc.h"

/*******************************************************************************
 * Definitions
 ******************************************************************************/


/*******************************************************************************
 * Variables
 ******************************************************************************/
char gAppPrintfBuffer[256];


/*******************************************************************************
 * Prototypes
 ******************************************************************************/
void App_BootClockRUN(void);
void App_Tick_PeriodicalCallback(void);
void App_OLED_ShowCamera(void);

/*******************************************************************************
 * Code
 ******************************************************************************/
/*!
 * @brief Main function
 */
int main(void)
{
    /* Init board hardware. */
    BOARD_InitBootPins();
    BOARD_BootClockRUN();
    App_BootClockRUN(); /* Enable the clocks additionally not in BOARD_BootClockRUN(). */

    /* Initialize debug console. */
    BOARD_InitDebugConsole(); /* Flexcomm0 - UART0, 115200. */

    PRINTF("\r\nApp_DMA_Camera Demo.\r\n");
    PRINTF("build time: %s, %s\r\n", __TIME__, __DATE__);

    OLED_Init();
    OLED_PrintReset();
    OLED_PrintStr("Camera Demo.\r\n");

    Tick_Init(200UL); /* 5ms per tick. */
    BTN_Init();
    Tick_InstallPeriodicalCallback(1U, App_Tick_PeriodicalCallback);

    Camera_Init();

    while (1)
    {
        Camera_StartCapture();
        App_OLED_ShowCamera();
    }
}

/* 启用在BOARD_BootClockRUN()函数中未启用的时钟 */
void App_BootClockRUN(void)
{
    CLOCK_EnableClock(kCLOCK_Gpio0);
    CLOCK_EnableClock(kCLOCK_Gpio1);
    CLOCK_EnableClock(kCLOCK_InputMux);
    CLOCK_EnableClock(kCLOCK_Sct0);
    CLOCK_EnableClock(kCLOCK_Dma);
}

/* 由Systick周期调用的回调函数 */
void App_Tick_PeriodicalCallback(void)
{
    BTN_WaitBlockingHook();
}

/* DMA传输完成中断 */
void DMA0_IRQHandler(void)
{
    uint32_t flags = DMA_GetChannelsOnInterruptA(DMA0);

    /* 处理摄像头数据搬运事件 */
    if (0U != (flags & (1U << CAMERA_DMA_CHANNEL_IDX)))
    {
        Camera_DmaIRQHandlerHook();
    }
    DMA_ClearFlagsOnInterruptA(DMA0, flags);
}

/* 实现隔点采样后，将从摄像头采集的320x240数据压缩成OLED可显示的128*64个点
 ******** 横向5个像素，纵向4个像素合并成一个数据，最后空出来来4个像素行
 * 横向2个像素，纵向4个像素合并成一个数据，剩下的留空
 */

//#define APP_CAMERA_DATA_LIGHT_SHRESHOLD (0x380) /* 方圆四个像素合并成一个显示点,即16个像素作为一个点显示 */
#define APP_CAMERA_DATA_LIGHT_SHRESHOLD 0x40
uint8_t gOledDisplayBuffer[OLED_LINE_COUNT_MAX][OLED_ROW_COUNT_MAX];

void App_CompressShowData(void)
{
    uint32_t line, row; /* OLED显示的行和列编号 */
    uint32_t camLine, camRow, camLineOffset, camRowOffset;
    uint32_t bIdx;
    uint32_t camDatAcc; /* 抽取要显示的点 */
    uint8_t  dat;

    for (line = 0U; line < OLED_LINE_COUNT_MAX-1U; line++)
    {
        for (row = 0U; row < (OLED_ROW_COUNT_MAX); row++)
        {
            dat = 0U;
            for (bIdx = 0U; bIdx < 8U; bIdx++)
            {
#if 0
                camLineOffset = 4U * (line * 8U + bIdx );
                camRowOffset  = 5U * row;
                camDatAcc = 0U;
                /* 累加采样光强度能量 */
                for (camLine = 0U; camLine < 4U; camLine++ ) /* 纵向4个像素压缩成一个显示点 */
                {
                    for (camRow = 0U; camRow < 5U; camRow++ ) /* 横向5个像素压缩成一个显示点 */
                    {
                        camDatAcc += gCameraPixelData[ (4U * (line * 8U + bIdx)/*+ camLine*/) * CAMERA_PIXELS_PER_LINE
                                                   + (5U * row                + camRow ) ];
                    }
                }
#else
                camDatAcc = gCameraPixelData[  2U * (line * 8U + bIdx) * CAMERA_PIXELS_PER_LINE2 /* 寻址行 */
                                             + 2U * row]; /* 寻址列 */
#endif
                /* 首先将原始数据进行二值化 */
                if (camDatAcc > APP_CAMERA_DATA_LIGHT_SHRESHOLD)
                {
                    //dat |= (1U << (7U-bIdx));
                    dat |= (1U << bIdx);
                }
            }
            gOledDisplayBuffer[line][/* OLED_ROW_COUNT_MAX-1U-*/row] = dat;
        }
    }
}

void App_OLED_ShowCamera(void)
{
    uint32_t line;

    App_CompressShowData();
    for (line = 0U; line < OLED_LINE_COUNT_MAX; line++)
    {
        OLED_WriteLine(line, 0U, gOledDisplayBuffer[line], OLED_ROW_COUNT_MAX);
    }
}

/* EOF. */
